package com.xzg.servlet;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.xzg.annotation.XzgController;
import com.xzg.annotation.XzgQualifier;
import com.xzg.annotation.XzgRequestMapping;
import com.xzg.annotation.XzgService;
import com.xzg.controller.XzgDemoController;
import com.xzg.handlerAdapter.HandlerAdapterService;

public class DispatcherServlet extends HttpServlet {
	// 存放路径名
	List<String> classNames = new ArrayList<String>();
	// 存放bean
	Map<String, Object> bean = new HashMap<String, Object>();
	// 存放映射bean
	Map<String, Object> handlerbean = new HashMap<String, Object>();

	private static final long serialVersionUID = 555205127789252951L;

	@Override
	public void init(ServletConfig config) throws ServletException {
		// 首先把地址的类加入到classNames容器中
		scanPackgae("com.xzg");
		for (String className : classNames) {
			System.out.println(className);
		}
		// 将加载进来的路径进行实例化，加到map中
		instance();
		// service注入到controller中的属性中
		ioc();
		// 将requestMapping和url关联起来
		HandlerMapping();
		for (Map.Entry<String, Object> entry : handlerbean.entrySet()) {
			System.out.println(entry.getKey() + ":" + entry.getValue());
		}
	}

	private void HandlerMapping() {
		if (bean.entrySet().isEmpty()) {
			System.out.println("类没有进行实例化");
			return;
		}
		// 遍历bean容器
		for (Map.Entry<String, Object> entyr : bean.entrySet()) {
			Object obj = entyr.getValue();
			Class<?> clazz = obj.getClass();
			// 类是否有controller注解
			if (clazz.isAnnotationPresent(XzgController.class)) {
				// 获取requestMapping value值
				XzgRequestMapping xzgRequestMapping = clazz.getAnnotation(XzgRequestMapping.class);
				String classpath = xzgRequestMapping.value();
				Method[] methods = clazz.getMethods();
				// 遍历所有方法上的requestMapping的值
				for (Method method : methods) {
					if (method.isAnnotationPresent(XzgRequestMapping.class)) {
						XzgRequestMapping methodReq = method.getAnnotation(XzgRequestMapping.class);
						String methodPath = methodReq.value();
						// 类mapping的值和方法上的值 都放入map中
						handlerbean.put(classpath + methodPath, method);
					} else {
						continue;
					}
				}
			} else {
				continue;
			}
		}
	}

	private void ioc() {
		if (bean.isEmpty()) {
			System.out.println("扫描失败 ---------------");
			return;
		}
		for (Map.Entry<String, Object> entry : bean.entrySet()) {
			// 获取类
			Object instance = entry.getValue();
			Class<?> clazz = instance.getClass();
			// 如果是Controller 我就进行注入
			if (clazz.isAnnotationPresent(XzgController.class)) {
				// 获取所有属性
				Field[] fields = clazz.getDeclaredFields();
				// 遍历所有属性
				for (Field field : fields) {
					if (field.isAnnotationPresent(XzgQualifier.class)) {
						// 获取属性注解
						XzgQualifier qualifier = field.getAnnotation(XzgQualifier.class);
						// 获取value值
						String key = qualifier.value();
						// 放开权限
						field.setAccessible(true);
						try {
							field.set(instance, bean.get(key));
						} catch (IllegalArgumentException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (IllegalAccessException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					} else {
						continue;
					}
				}
			} else {
				continue;
			}

		}
	}

	private void instance() {
		if (classNames.isEmpty()) {
			System.out.println("扫描失败 ---------------");
			return;
		}
		for (String className : classNames) {
			// 去除后缀的.class
			String cn = className.replaceAll(".class", "");
			try {
				Class<?> clazz = Class.forName(cn);
				// 如果是Controller
				if (clazz.isAnnotationPresent(XzgController.class)) {
					XzgRequestMapping requestMapping = clazz.getAnnotation(XzgRequestMapping.class);
					Object instance = clazz.newInstance();
					bean.put(requestMapping.value(), instance);
				}
				// 如果是service注解
				else if (clazz.isAnnotationPresent(XzgService.class)) {
					XzgService xzgService = clazz.getAnnotation(XzgService.class);
					Object instance = clazz.newInstance();
					bean.put(xzgService.value(), instance);
				} else {
					continue;
				}
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	private void scanPackgae(String basePackage) {
		//// 扫描编译好的类路径下所有的类
		URL url = this.getClass().getClassLoader().getResource("/" + replaceTo(basePackage));
		// 获取路径
		String fileStr = url.getFile();
		// 通过路径new File类
		File file = new File(fileStr);
		// 获取路径下的文件
		String[] filenames = file.list();
		// 遍历文件
		for (String filename : filenames) {
			File filePath = new File(fileStr + filename);
			// 如果是文件夹 继续递归寻找
			if (filePath.isDirectory()) {
				scanPackgae(basePackage + "." + filename);
			} else {
				// 是class就加入list中
				classNames.add(basePackage + "." + filePath.getName());
			}
		}
	}

	private String replaceTo(String basePackage) {
		return basePackage.replaceAll("\\.", "/");
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 先获取请求的路径
		String url = req.getRequestURI();
		// 在获取项目路径
		String context = req.getContextPath();
		// 然后获取项目之后的url，通过这取得method
		String path = url.replace(context, "");
		// 然后获取方法
		Method method = (Method) handlerbean.get(path);
		// 然后通过url取得contoller
		XzgDemoController clazz = (XzgDemoController) bean.get("/" + path.split("/")[1]);
		// 在bean里面获取解析器
		HandlerAdapterService ad = (HandlerAdapterService) bean.get("XzgHandlerAdapter");
		// 调用方法获取参数
		Object[] obj = ad.hand(req, resp, method, bean);
		try {
			// 反射调用
			method.invoke(clazz, obj);
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
